﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CardLib
{
    public class Card:IComparable, ICloneable
    {
        public readonly CardRank Rank;
        public readonly CardSuit Suit;

        public static bool UseTrump = false;
        public static CardSuit Trump = CardSuit.Spade;

        public static bool UseWild = false;

        public static bool IsAceHigh = true;
        public static bool IsDeuceHigh = true;

        public Card()
        {
            Suit = CardSuit.Spade;
            Rank = CardRank.Three;
        }

        public Card(CardSuit newSuit, CardRank newRank)
        {
            if ((newSuit == CardSuit.Joker && newRank < CardRank.BlackJoker)
                || (newSuit != CardSuit.Joker && newRank > CardRank.Deuce))
                throw new System.ArgumentException("The rank of card does NOT match the suit. " +
                    "Suit: " + newSuit.ToString() + ", Rank: " + newRank.ToString());
            else
            {
                Suit = newSuit;
                Rank = newRank;
            }
        }

        /// <summary>
        /// For test.
        /// </summary>
        /// <param name="newSuit"></param>
        /// <param name="newRank"></param>
        /// <param name="fixRank"></param>
        public Card(CardSuit newSuit, CardRank newRank, bool fixRank)
        {
            if (fixRank)
            {
                if (newSuit == CardSuit.Joker && newRank < CardRank.BlackJoker)
                    newRank = (CardRank)((int)newRank % 2 + (int)CardRank.BlackJoker);

                if ((newSuit != CardSuit.Joker && newRank > CardRank.Deuce))
                    newRank = (CardRank)((int)newRank - 2);
            }
            else
            {
                if ((newSuit == CardSuit.Joker && newRank < CardRank.BlackJoker)
                    || (newSuit != CardSuit.Joker && newRank > CardRank.Deuce))
                    throw new System.ArgumentException("The rank of card does NOT match the suit. " +
                        "Suit: " + newSuit.ToString() + ", Rank: " + newRank.ToString());
            }

            Suit = newSuit;
            Rank = newRank;
        }

        public Object Clone()
        {
            return MemberwiseClone();
        }

        public override string ToString()
        {
            string strSuit;
            string strRank;

            switch (Suit)
            {
                case CardSuit.Spade:
                    //strSuit = "♠";
                    strSuit = Convert.ToString(Char.ConvertFromUtf32(6));
                    break;
                case CardSuit.Heart:
                    //strSuit = "♥";
                    strSuit = Convert.ToString(Char.ConvertFromUtf32(3));
                    break;
                case CardSuit.Club:
                    //strSuit = "♣";
                    strSuit = Convert.ToString(Char.ConvertFromUtf32(5));
                    break;
                case CardSuit.Diamond:
                    //strSuit = "♦";
                    strSuit = Convert.ToString(Char.ConvertFromUtf32(4));
                    break;
                case CardSuit.Joker:
                    //strSuit = "J";
                    strSuit = Convert.ToString(Char.ConvertFromUtf32(74));
                    break; 
                default:
                    strSuit = "";
                    break;
            }

            switch (Rank)
            {                
                case CardRank.Three:

                case CardRank.Four:

                case CardRank.Five:

                case CardRank.Six:
 
                case CardRank.Seven:

                case CardRank.Eight:

                case CardRank.Nine:

                case CardRank.Ten:
                    strRank = Convert.ToString((int)Rank);
                    break;
                case CardRank.Jack:
                    strRank = "J";
                    break;
                case CardRank.Queen:
                    strRank = "Q";
                    break;
                case CardRank.King:
                    strRank = "K";
                    break;
                case CardRank.Ace:
                    strRank = "A";
                    break;
                case CardRank.Deuce:
                    strRank = "2";
                    break;
                case CardRank.BlackJoker:
                    strRank = Convert.ToString((char)(Rank - 15));
                    break;
                case CardRank.RedJoker:
                    strRank = Convert.ToString((char)(Rank - 15));
                    break;
                default:
                    strRank = "";
                    break;
            }

            return strSuit + strRank;
        }

        #region Operator Overide

        public static bool operator ==(Card card01, Card card02)
        {
            return card01.Rank == card02.Rank;
        }

        public static bool operator !=(Card card01, Card card02)
        {
            return !(card01 == card02);
        }

        public override bool Equals(object card)
        {
            return this == (Card)card;
        }

        public override int GetHashCode()
        {
            return (int)this.Suit * 100 + (int)this.Rank;
        }

        public static bool operator >(Card card01, Card card02)
        {
            return card01.Rank > card02.Rank;
        }

        public static bool operator >=(Card card01, Card card02)
        {
            return (card01 > card02) || (card01 == card02);
        }

        public static bool operator <(Card card01, Card card02)
        {
            return !(card01 >= card02);
        }

        public static bool operator <=(Card card01, Card card02)
        {
            return !(card01 > card02);
        }

        #endregion

        public int CompareTo(object obj)
        {
            return this.Rank - ((Card)obj).Rank;
        }
    }

    public class SuitComparer:IComparer<Card>
    {
        public int Compare(Card card1, Card card2)
        {
            return card1.Suit - card2.Suit;
        }
    }
}
